package edu.towson.forensics.securephone;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.android.ddmlib.AdbCommandRejectedException;
import com.android.ddmlib.AndroidDebugBridge;
import com.android.ddmlib.IDevice;
import com.android.ddmlib.MultiLineReceiver;
import com.android.ddmlib.TimeoutException;


class BooleanResultReader extends MultiLineReceiver {
	private final boolean[] mResult;

	public BooleanResultReader(boolean[] result) {
		mResult = result;
	}

	@Override
	public void processNewLines(String[] strings) {
		if (strings.length > 0) {
			Pattern pattern = Pattern.compile(".*?\\([0-9]{8} ([0-9]{8}).*");
			Matcher matcher = pattern.matcher(strings[0]);
			if (matcher.matches()) {
				if (Integer.parseInt(matcher.group(1)) == 1) {
					mResult[0] = true;
				}
			}
		}
	}

	public boolean isCancelled() {
		return false;
	}
}

public class ADBConnection {

//	private String adbSendingCommand;
	private String SERVER_CONNECTION_LOOPBACK_IP="127.0.0.1";
	private int PC_PORT_NO=0;
	private int PHONE_PORT_NO=0;
	private String SECURE_PHONE_ID = "015D94F406021006";
	
	AndroidDebugBridge adb=null;
	IDevice currentDevice=null;
	
	Socket socket = null;
	BufferedWriter out = null;
	BufferedReader in=null;

	//set the port numbers and device ID
	public ADBConnection(int pcPortNumber,int phonePortNumber,String securePhoneId){
		PC_PORT_NO=pcPortNumber;
		PHONE_PORT_NO=phonePortNumber;
		SECURE_PHONE_ID=securePhoneId;
	}

	void runADBCommand(String adbCommand) throws Exception {
		boolean[] result = new boolean[1];
 
		if (currentDevice.isOnline()) {
			//** Execute a Linux shell command on phone 
			currentDevice.executeShellCommand(adbCommand, new BooleanResultReader(result));
		}
	}
	
	
	/** Check the list of available Devices and if the ID is not match that will call UnSecurePhone otherwise
	 *  will forward a given port number in PC side to specific port number in Phone  
	 */	
	boolean chkDeviceId() throws Exception {
		currentDevice = null;
		if (adb.getDevices()!=null)
		{
			for (IDevice device : adb.getDevices()) { //System.out.println(device.getSerialNumber().toString());
				if (device.getSerialNumber().equals(SECURE_PHONE_ID)) {
					currentDevice = device;	
					return true;
				}				
			}			
			if (currentDevice==null)
				ProvidedFunctions.NotSecurePhone();
		}
		System.out.println("No Android device has been connected.");
		return false;
		}
	
	protected boolean forwardport(){
		try {
			currentDevice.createForward(PC_PORT_NO, PHONE_PORT_NO);
		} catch (TimeoutException e) {
			// TODO Auto-generated catch block
			System.out.println(e.getMessage());
			return false;
		} catch (AdbCommandRejectedException e) {
			// TODO Auto-generated catch block
			System.out.println(e.getMessage());
			return false;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			System.out.println(e.getMessage());
			return false;
		}
		return true;
	}

	@Deprecated()
	protected boolean isAdbConnected()
	{
		try {
			chkDeviceId();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return false;
	}

	@Deprecated
	boolean isConnedcted() {
		Socket socket = null;
		try {
			Thread.sleep(3000);
		} catch (InterruptedException e1) {
			e1.printStackTrace();
		}

		socket = new Socket();

		try {
			socket.connect(new InetSocketAddress(SERVER_CONNECTION_LOOPBACK_IP, PC_PORT_NO));
		} catch (IOException e) {
			return false;
		}

		try {
			socket.close();
		} catch (IOException e) {
			return false;
		}
		return true;
	}	
	

	protected boolean connectToAdb(String adbLocation)  {
		
		adb=null;		
		try {
			AndroidDebugBridge.init(false);
			adb = AndroidDebugBridge.createBridge(adbLocation,true);
		} 
		catch (Exception e){
			System.out.println(e.getMessage());
			return false;
		}		
		return true;
	}
	
	protected boolean connectToPhone(){
		
		if (this.forwardport())
		{	
		
		// TODO: Maybe this waiting wouldn't be necessary
//		try{
//		Thread.sleep(2500);
//		} catch (InterruptedException e) {
//			System.out.println(e.getMessage());
//		}
		
		socket = new Socket();
		try {
			socket.connect(new InetSocketAddress(SERVER_CONNECTION_LOOPBACK_IP, PC_PORT_NO));
			in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));			
			return true;
			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			System.out.println(e.getMessage());
		}		
		}
		
		return false;
	}
	
	protected void terminateSocketConnection() {
		try {
			if (out != null) 
				out.close();				
			if (in != null) 
				in.close();
			if (socket!= null) 
				socket.close();			
		} catch (IOException e) {
			System.out.println(e.getMessage());
		}
	}

	protected void disconnectFromPhone() {

		try 
		{
			//System.out.println("==> cleanUp");

			out.write("finish");
			out.newLine();
			out.flush();
		}
		
		catch (IOException e) 
		{
			System.out.println(e.getMessage());
		}
		
		finally 
		{ 
			this.terminateSocketConnection();
		}
	}
	
	protected String phoneMacAddress() {
		String macAddress=null;

		try 
		{
			System.out.println("==> phoneMacAddress");

			out.write("phoneMacAddress");
			out.newLine();
			out.flush();
						
			if (!in.ready())
				macAddress=in.readLine();			
		} 
		
		catch (IOException ex) 
		{
			ex.printStackTrace();
		} 
		
		return macAddress;			
	}
	
	protected void sendDataToPhone(PhoneRequestedCommands CommandFromPhone)
	{
		switch (CommandFromPhone) 
		{
		case pcMac:
					try
					{
						out.write(ProvidedFunctions.pcMacAddress());
						out.newLine();
						out.flush();
					}
					catch (IOException e)
					{
						System.out.println(e.getMessage());	
					}
					break;
					
		default:
			break;
		}	
	}
	
}
